mod file;
mod input;

use std::{
    fs::File,
    io::{self, BufRead, BufReader, Write},
};

const OUT_PATH: &str = "resources/out.txt";

fn main() {
    // let args: Vec<String> = std::env::args().collect();
    let args: Vec<String> = vec![
        "1".to_string(),
        "resources/f1.txt".to_string(),
        "resources/f2.txt".to_string(),
    ];

    main_action(args).unwrap();
}

fn main_action(args: Vec<String>) -> Result<(), String> {

    let in_args = input::input_from_args(&args)?;

    let (f1, f2) = input::open_files(&in_args)?;

    let mut out: Vec<u8> = Vec::new();
    read_from_file(&f1, &f2, &mut out).map_err(|e| e.to_string())?;

    write_to_file(&out)?;

    println!("Done.");

    Result::Ok(())
}

struct FileSource<'a> {
    reader: BufReader<&'a File>,
    finished: bool,
    s_number: u32
}

impl FileSource<'_> {
    fn get_next(&mut self) -> Result<file::Line, io::Error> {
        let mut l1 = String::new();
        self.finished = self.reader.read_line(&mut l1).map(|s| s == 0)?;
        self.s_number += 1;

        Result::Ok(
            file::Line { number: self.s_number - 1, content: l1 }
        )
    }

    fn create(file: &File) -> FileSource {
        FileSource { reader: io::BufReader::new(file), finished: false, s_number: 0 }
    }
}

fn read_from_file(f1: &File, f2: &File, out: &mut Vec<u8>) -> Result<(), io::Error> {
    
    let mut fs1 = FileSource::create(f1);
    let mut fs2 = FileSource::create(f2);

    while !fs1.finished || !fs2.finished {
        let line1 = fs1.get_next()?;
        let line2 = fs2.get_next()?;

        if line1 == line2 {
            out.write(line1.content.as_bytes())?
        } else {
            out.write(line1.content.as_bytes())?
        };
    }

    Result::Ok(())
}

fn write_to_file(data: &Vec<u8>) -> Result<usize, String> {
    let mut out_f = File::create(OUT_PATH).map_err(|e| e.to_string())?;

    out_f.write(data).map_err(|e| e.to_string())
}